/*
Automatic clinic tests using a robot arm.
Copyright (C) 2010  CIC-CPC, CHU Gabriel Montpied
All other trademarks, logos and copyrights are the property
of their respective owners.

This file is part of cpc-painbot.

cpc-painbot is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpc-painbot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with cpc-painbot.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "testbras.h"

#include <QTextCodec>
#include <QSignalSpy>
#include <QTest>
#include <QDebug>

#include "positionbras.h"
#include "bras.h"
#include "commande/bras/ping.h"
#include "commande/bras/init.h"
#include "commande/bras/position.h"
#include "commande/bras/lireposition.h"
#include "commande/bras/deplacerarc.h"
#include "commande/bras/deplacerlineaire.h"
#include "commande/bras/deplacerptp.h"

void TestBras::initTestCase()
{
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
}

void TestBras::testPositionBras_data()
{
    QTest::addColumn<qreal>("x");
    QTest::addColumn<qreal>("y");
    QTest::addColumn<qreal>("z");
    QTest::addColumn<qreal>("r");
    QTest::addColumn<bool>("valide");

    QTest::newRow("origine")        << 0. << qreal(PositionBras::YMax) << 0. << 0. << true;
    QTest::newRow("extreme-gauche") << qreal(PositionBras::XMin) << 0. << 0. << 0. << true;
    QTest::newRow("extreme-droite") << qreal(PositionBras::XMax) << 0. << 0. << 0. << true;
    QTest::newRow("inv-gauche-max") << -100. << qreal(PositionBras::YMax) << 0. << 0. << false;
    QTest::newRow("inv-droite-max") << 100. << qreal(PositionBras::YMax) << 0. << 0. << false;
    QTest::newRow("inv-gauche-min") << -100. << 10. << 0. << 0. << false;
    QTest::newRow("inv-droite-min") << 100. << 10. << 0. << 0. << false;
}

void TestBras::testPositionBras()
{
    QFETCH(qreal, x);
    QFETCH(qreal, y);
    QFETCH(qreal, z);
    QFETCH(qreal, r);
    QFETCH(bool, valide);

    PositionBras pos(x, y, z, r, PositionBras::Droitier);

    QCOMPARE(pos.isValide(), valide);

    if ( !valide ) {
        pos.ajuster();
        QVERIFY(pos.isValide());
    }
}

void TestBras::testCommandePing()
{
    commande::Commande * ping = new commande::bras::Ping;
    QString ping_attendu = QString(19, '\x000');
    ping_attendu.replace(0, 4, "\x003\x010\x041\x030").replace(18, 1, '\x071');


    QCOMPARE(ping->generer().toAscii(), ping_attendu.toAscii());

    delete ping;
}

void TestBras::testCommandeInit()
{
    commande::bras::Init init;
    QString init_attendu = "@R0\r";

    QCOMPARE(init.generer(), init_attendu);
    QCOMPARE(init.generer().toAscii(), init_attendu.toAscii());
}

void TestBras::testCommandeLirePosition()
{
    commande::bras::LirePosition lirepos;
    QString lirepos_attendu = "@N1\r";
    QCOMPARE(lirepos.generer(), lirepos_attendu);
    QCOMPARE(lirepos.generer().toAscii(), lirepos_attendu.toAscii());
}

void TestBras::testCommandeDeplacer()
{
    commande::bras::DeplacerPTP ptp;
    commande::bras::DeplacerLineaire ctp_lin;
    commande::bras::DeplacerArc ctp_arc;
    PositionBras position(16.4, 150, 25, 47, PositionBras::Gaucher);
    QString serial = "@M1,1,16.400,150.000,25.000,47.000\r";

    ptp.setArrivee(position);

    QCOMPARE(ptp.arrivee(), position);
    QCOMPARE(ptp.generer(), serial);
    QCOMPARE(ptp.generer().toAscii(), serial.toAscii());

    serial = "@M2,15.5,1,16.400,150.000,25.000,47.000\r";
    ctp_lin.setArrivee(position);
    ctp_lin.setVitesse(15.5);
    QCOMPARE(ctp_lin.generer(), serial);
    QCOMPARE(ctp_lin.generer().toAscii(), serial.toAscii());

    QCOMPARE(ctp_lin.arrivee(), position);
    QCOMPARE(ctp_lin.vitesse(), float(15.5));

    serial = "@M3,23,0,11.200,150.000,25.000,47.000,15.5,1,16.400,150.000,25.000,47.000\r";
    ctp_arc.setArrivee(position);
    ctp_arc.setVitesseArrivee(15.5);
    ctp_arc.setVitesseArc(23);
    ctp_arc.setArc(PositionBras(11.2, 150, 25, 47));

    QCOMPARE(ctp_arc.arrivee(), position);
    QCOMPARE(ctp_arc.vitesseArrivee(), float(15.5));
    QCOMPARE(ctp_arc.arc(), PositionBras(11.2, 150, 25, 47));
    QCOMPARE(ctp_arc.vitesseArc(), float(23.));
    QCOMPARE(ctp_arc.generer(), serial);
    QCOMPARE(ctp_arc.generer().toAscii(), serial.toAscii());
}

void TestBras::testRegexCommande_data()
{
    commande::bras::Ping ping;
    commande::bras::Init init;
    commande::bras::LirePosition lirepos;

    QTest::addColumn<QString>("serial");
    QTest::addColumn<bool>("validite");

    // Cas des commandes
    QTest::newRow("Ping") << ping.generer() << false;
    QTest::newRow("Init") << init.generer() << true;
    QTest::newRow("LirePosition") << lirepos.generer() << true;

    // Pas vérifiés.
    QTest::newRow("Pas de fin") << "@Rx" << false;
    QTest::newRow("Pas de début") << "r0,123\r" << false;
    QTest::newRow("champ vide") << "@r0,123,\r" << false;
    QTest::newRow("Mauvais code") << "@r01,123\r" << false;
    QTest::newRow("Champ vide au milieu") << "@r0,aze,,123\r" << false;
}

void TestBras::testRegexCommande()
{
    QFETCH(QString, serial);
    QFETCH(bool, validite);
    QRegExp format("^@\\w\\w(?:,[^,]+)*\\r$");

    format.setMinimal(true);

    // Cas des commandes.
    QVERIFY(format.exactMatch(serial) == validite);
}

void TestBras::testFabriqueCommande_data()
{
    QTest::addColumn<QString>("serial");
    QTest::addColumn<bool>("existe");

    QTest::newRow("Init") << "@R0\r" << true;
    QTest::newRow("Position") << "@n1,0,12.3,200,45.5,-25.6\r" << true;
    QTest::newRow("LirePosition") << "@N1\r" << true;

    QTest::newRow("Invalide") << "@X4\r" << false;
}

void TestBras::testFabriqueCommande()
{
    QFETCH(QString, serial);
    QFETCH(bool, existe);
    commande::Commande * fabrique = commande::bras::Caracteres::lire(serial);

    if ( existe ) {

        QVERIFY(fabrique != 0);
        QCOMPARE(fabrique->generer(), serial);
        delete fabrique;
    } else
        QVERIFY(fabrique == 0);
}
